with Cairo, Cairo.Context, Cairo.Surface, Cairo.Font_Face;
with Performances;
with Interfaces.C;
with Legend.Colors;
private with Ada.Finalization;
package Legend.Renders is

   -- 渲染工作由画布(Canvas)，画师(Painter)，发布者(Publisher)协同完成
   -- Canvas维护一个像素缓冲区, 并提供SDL及Cairo接口供Painter使用
   -- Painter负责实际的绘制工作
   -- Publisher负责检查Canvas是否需要更新, 如需更新则通知Painter重绘Canvas
   
   Full_Canvas : constant SDL.Video.Rect_t := (0, 0, 0, 0);

   ---------------------------------------------------------------------- 

   -- callback interface for canvas
   type Painter_Type is limited interface;

   -- you should implement it by using As_Surface or As_Brush
   procedure Paint (this : in out Painter_Type) is abstract;

   
   ---------------------------------------------------------------------- 

   -- wrap sdl surface with cairo image surface 
   -- call Painter.Paint if cavnas is set to dirty (Invalidate)
   type Canvas_Type (
      Painter : not null access Painter_Type'Class
      ) is tagged limited private;

   -- bind sdl surface, and then create brush 
   procedure Bind (
      this        : in out Canvas_Type;
      Region      : SDL.Video.Rect_t := Full_Canvas; -- layout at screen
      Save_Region : Boolean := False                 -- make a region copy ?
      );

   -- retrieve sdl sruface
   function As_Surface (
      this : Canvas_Type
      ) return SDL.Video.Surface_Access_t;

   -- retrieve cairo context
   function As_Brush (
      this : Canvas_Type
      ) return Cairo.Context.Cairo_Context_Ref;

   -- retrieve render performance watcher
   function Get_Performance (
      this : Canvas_Type
      ) return Performances.Monitor_Pointer;

   -- mark canvas to dirty state,
   -- frame render task will repaint canvas at next interval
   procedure Invalidate (this : in out Canvas_Type);

   -- repaint canvas by calling Painter.Paint
   procedure Repaint (this : in out Canvas_Type'Class);

   -- make a copy of screen overlap region
   procedure Save_Overlap_Surface (this : in out Canvas_Type'Class);

   -- restore origin surface of screen overlap region
   procedure Restore_Overlap_Surface (this : in out Canvas_Type'Class);

   -- create a surface compiliant with cairo ARGB image surface
   function Create_SDL_Surface (
      Width, Height : Uint16_t
      ) return SDL.Video.Surface_Access_t;

   -- set brush font by name
   procedure Set_True_Font (
      this   : in out Canvas_Type;
      Family : String := "Default"
      );

   procedure Set_True_Font_Style (
      this   : in out Canvas_Type;
      Italic : Boolean := False;
      Bold   : Boolean := False
      );

   procedure Set_Brush_Color (
      this  : in out Canvas_Type;
      Color : Color_Type
      );

   function To_Cairo_Color (
      this : Canvas_Type;
      C    : Color_Type
      ) return Uint32_t with Inline;

   procedure Clear (
      this : in out Canvas_Type;
      Color : Color_Type := Colors.Black
      );

--   -- this method implement by sdl_ttf
--   procedure Draw_Text (
--      this : in out Canvas_Type;
--      Text : UTF8_String;
--      Where : Point_Type;
--      Color : Color_Type;
--      Family : String := "Default";
--      Size   : Natural := 16;
--      Flip  : Boolean := False
--      );
--
   procedure Draw_Picture (
      this      : in out Canvas_Type;
      Picture   : Picture_Type;
      Position  : Point_Type
      );

   procedure Draw_Canvas (
      this     : in out Canvas_Type;
      Source   : Canvas_Type'Class;
      Position : Point_Type
      );

   procedure Draw_Movie (
      this     : in out Canvas_Type;
      Movie    : in out Movie_Type;
      Position : Point_Type
      );

   procedure Draw_Round_Rect (
      this       : in out Canvas_Type;
      Region     : SDL.Video.Rect_t; 
      Back_Color : Color_Type := Colors.Black;
      Fore_Color : Color_Type := Colors.White;
      Width      : Interfaces.C.double := 2.0;
      Groove     : Boolean := True
      );

   procedure Draw_Border (
      this   : in out Canvas_Type;
      Color  : Color_Type := Colors.White;
      Width  : Interfaces.C.double := 2.0;
      Groove : Boolean := True
      );

   -- convert cairo premultipled ARGB surface to sdl surface
   -- see http://cairographics.org/SDL/ for more detail
   procedure Accept_Brush_Changed (this : in out Canvas_Type);

   -- convert sdl surface to cairo surface
   procedure Accept_SDL_Changed (this : in out Canvas_Type);

   procedure Update_Screen (this : in out Canvas_Type);

   -- show surface on screen at this.Region
   procedure Show (
      this : in out Canvas_Type;
      Surface : SDL.Video.Surface_Access_t
      ) with Inline;

   function Make_Shadow (
      Color  : Color_Type;
      Width  : Uint16_t := 18; 
      Height : Uint16_t := 9
      )  return SDL.Video.Surface_Access_t;

   procedure Set_To_Opaque (Picture : in out Picture_Type);

   function Display_Width (Text : UTF8_String) return Natural;


   Screen : SDL.Video.Surface_Access_t;

   procedure Initialize;

   procedure Finalize;

   procedure Toggle_Fullscreen;

private
   use Ada.Finalization;


   type Canvas_Type (
      Painter : not null access Painter_Type'Class
      )  is new Limited_Controlled with record
      Surface        : SDL.Video.Surface_Access_t;         -- sdl surface
      Surface_Handle : Cairo.Surface.Cairo_Surface_Handle; -- image surface
      Context_Handle : Cairo.Context.Cairo_Context_Handle; -- brush
      Region         : SDL.Video.Rect_t; -- which screen region was overlapped
      Overlap        : SDL.Video.Surface_Access_t; -- copy of screen region
      Version        : Version_Type; -- indicate wheather canvas has changed
      Performance    : aliased Performances.Monitor_Type; -- watch render speed
      Font_Handle    : Cairo.Font_Face.Cairo_Font_Face_Handle; 
      Font_Ref       : Cairo.Font_Face.Cairo_Font_Face_Ref;
   end record;

   overriding
   procedure Initialize (this : in out Canvas_Type);

   overriding
   procedure Finalize (this : in out Canvas_Type);

end Legend.Renders;
